#include <assert.h>
#include <ctype.h>
#include <locale.h>
#include <errno.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <pthread.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include<windows.h>


void trivial_use_of_X_macros_for_printfs(void)
{
    printf("***** trivial_use_of_X_macros_for_printfs *****\n");
    /* define a list of preprocessor tokens on which to call X */
    #define X_123 X(1) X(2) X(3)
    /* define X to use */
    #define X(val) printf("X(%d) made this print\n", val);
    X_123;
    #undef X
    /* good practice to undef X to facilitate reuse later on
        取消定义 X 以方便以后重用的良好做法
     */
}


void give_X_macro_as_an_argument(void)
{
    printf("***** give_X_macro_as_an_argument *****\n");
    /* declare list of items */
    #define ITEM_LIST(X) \
        X(item1) \
        X(item2) \
        X(item3) \
    /* end of list */

    /* define macro to apply */
    #define PRINTSTRING(value) printf( #value "\n");
    /* apply macro to the list of items */
    ITEM_LIST(PRINTSTRING);
}


/* declare items of the enum */
#define FOREACH \
    X(item1) \
    X(item2) \
    X(item3) \
/* end of list */
/* define the enum values */
#define X(id) MyEnum_ ## id,
    enum MyEnum { FOREACH };
#undef X

/* convert an enum value to its identifier */
const char * enum2string(int enumValue)
{
    const char* stringValue = NULL;
    #define X(id) if (enumValue == MyEnum_ ## id) stringValue = #id;
        FOREACH
    #undef X
    return stringValue;
}

void enum_value_and_identifier(void)
{
    printf("***** enum_value_and_identifier *****\n");
    printf("%s\n", enum2string(MyEnum_item2)); // item2
}

/*
X-Macros can be used for code generation, by writing repetitive code: iterate over a list to do some tasks, or to
declare a set of constants, objects or functions.
Here we use X-macros to declare an enum containing 4 commands and a map of their names as strings
Then we can print the string values of the enum.
*/
void cmdQuit(void)
{
    printf("***** cmdQuit *****\n");
    
}
void code_generation(void)
{
    printf("***** code_generation *****\n");
    /* All our commands */
    #define COMMANDS(OP) OP(Open) OP(Close) OP(Save) OP(Quit)
    /* generate the enum Commands: {cmdOpen, cmdClose, cmdSave, cmdQuit, }; */
    #define ENUM_NAME(name) cmd##name,
    enum Commands { COMMANDS(ENUM_NAME) };
    #undef ENUM_NAME

    /* generate the string table */ 
    #define COMMAND_OP(name) #name,
    const char* const commandNames[] = {
        COMMANDS(COMMAND_OP)
    };
    #undef COMMAND_OP
    /* the following prints "Quit\n": */
    printf("%s\n", (commandNames[cmdQuit])());
}


void main(void)
{
    trivial_use_of_X_macros_for_printfs();
    give_X_macro_as_an_argument();

    enum_value_and_identifier();
    
    code_generation();
    system("pause");
}